//gamedrawer.cpp
//draws the game to the screen
//maintains the UI and the gamestate


#include <math.h>
#include <sstream>
#include <vector>
#include <string>
#include "SOIL.h"
#include "game.h"
#include "gamedrawer.h"
#include "ui.h"
using namespace std;
#include <ctime>
#include <sys/timeb.h>
//used for debug
int GetMilliCount()
{
  // Something like GetTickCount but portable
  // It rolls over every ~ 12.1 days (0x100000/24/60/60)
  // Use GetMilliSpan to correct for rollover
  timeb tb;
  ftime( &tb );
  int nCount = tb.millitm + (tb.time & 0xfffff) * 1000;
  return nCount;
}



GameDrawer::GameDrawer(int w, int h) {
	loadTextures();
	ui = new UI(w,h);	
	game = new Game();
	window_width = w;
	window_height = h;	
}

GameDrawer::~GameDrawer() {
}

void GameDrawer::loadTextures(){
	textures.push_back(new Texture("Graphics\\blaster.png"));
	textures.push_back(new Texture("Graphics\\blueprint_mercury_combinator.png"));
	textures.push_back(new Texture("Graphics\\mercury.png"));
	textures.push_back(new Texture("Graphics\\mercury_blaster.png"));
	textures.push_back(new Texture("Graphics\\wall_section.png"));
	textures.push_back(new Texture("Graphics\\blueprint.png"));
	textures.push_back(new Texture("Graphics\\crystal1.png"));
	textures.push_back(new Texture("Graphics\\crystal2.png"));
	textures.push_back(new Texture("Graphics\\cargo_bot.png"));
	textures.push_back(new Texture("Graphics\\container.png"));
	textures.push_back(new Texture("Graphics\\reactor.png"));
	textures.push_back(new Texture("Graphics\\factory_blueprint.png"));
	textures.push_back(new Texture("Graphics\\metal1_plate.png"));
	textures.push_back(new Texture("Graphics\\metal1.png"));
	textures.push_back(new Texture("Graphics\\ore1.png"));
	textures.push_back(new Texture("Graphics\\storage.png"));
}

void GameDrawer::handleMouseInput(int button, int state, int x, int y ){
	mouse_set_position(x,y);
	if(button == GLUT_LEFT_BUTTON){
		if (state == GLUT_DOWN) {
			mouse_left_pressed();
		}
		else if(state == GLUT_UP){
			mouse_left_released();
		}	
	}
	if(button == GLUT_RIGHT_BUTTON){
		if (state == GLUT_DOWN) {
			mouse_right_pressed();
		}
		else if(state == GLUT_UP){
			mouse_right_released();
		}	
	}
	if(button == GLUT_MIDDLE_BUTTON){
		if (state == GLUT_DOWN) {
			mouse_middle_pressed();
		}
		else if(state == GLUT_UP){
			mouse_middle_released();
		}	
	}
	ui->handleMouseInput();
	game->handleMouseInput();
}

void GameDrawer::handleKeyboardInput(unsigned char key,int x,int y){
	x-=(int)get_camera_x();
	y-=(int)get_camera_y();
	game->handleKeyboardInput(key,x,y);
}

void GameDrawer::moveMouse(int x, int y){
	mouse_set_position(x,y);
	x-=(int)get_camera_x();
	y-=(int)get_camera_y();
}

void GameDrawer::moveActive(int x, int y){
	mouse_set_position(x,y);
	ui->mouseDragged();
}

void GameDrawer::step() {
						int t0, t1;
						t0 = GetMilliCount();
	game->update();
						t1 = GetMilliCount() - t0;					
						//printf("%i\n",t1);
}

void GameDrawer::draw() {
	fill(Color(155,155,125));
	noStroke();
	drawRect(0, 0, (float)window_width, (float)window_height);
	noFill();
	game->draw();
	ui->draw();
}

void GameDrawer::updateSize(int newW, int newH){
	window_width = newW;
	window_height = newH;
}

void GameDrawer::advance(float dt) {
	step();
}

string Texture::getName(){
	return name;
}
GLuint Texture::getID(){
	return ID;
}

void glEnable2D()
{
	int vPort[4];

   glGetIntegerv(GL_VIEWPORT, vPort);

   glMatrixMode(GL_PROJECTION);
   glPushMatrix();
   glLoadIdentity();

   glOrtho(0, vPort[2], 0, vPort[3], -1, 1);
   glMatrixMode(GL_MODELVIEW);
   glPushMatrix();
   glLoadIdentity();
}

void glDisable2D()
{
   glMatrixMode(GL_PROJECTION);
   glPopMatrix();   
   glMatrixMode(GL_MODELVIEW);
   glPopMatrix();	
}

void glTranslate2f(float x, float y){
	glTranslatef((float)x, (float)y, 0);
}

Color::Color(int rIn, int gIn, int bIn){
	r = (float) rIn/255;
	g = (float) gIn/255;
	b = (float) bIn/255;
	a = (float) 255/255;
}

Color::Color(int rIn, int gIn, int bIn, int aIn){
	r = (float) rIn/255;
	g = (float) gIn/255;
	b = (float) bIn/255;
	a = (float) aIn/255;
}

Color::Color(float rIn, float gIn,float bIn, float aIn){
	r = rIn;
	g = gIn;
	b = bIn;
	a = aIn;
}

Color::Color(float rIn, float gIn, float bIn){
	r = rIn;
	g = gIn;
	b = bIn;
	a = 1;
}

Coord::Coord(int xIn, int yIn){
		x = xIn;
		y = yIn;
}

void setColor(Color color){
	glColor4f(color.r,color.g,color.b,color.a);
}

void lineWidth(float width){
	if(width<4){
		glLineWidth(width);
	}
	else{
		glLineWidth(4);
	}
	
}

void circle_helper(float r){
		//                       1  2  3  4  5  6  7
		int line_list [8] = {0, 3, 4, 6, 7, 8, 8, 8};
		int number_of_lines = 0;

		if(r < 7){
			number_of_lines = line_list[(int)ceil(r)];
		}
		else if (r >= 7 && r < 16){
			number_of_lines = 12;
		}
		else if(r >= 16 && r < 50){
			number_of_lines = (int) ceil(r);
		}
		else{
			number_of_lines = (int) ceil(r*.5);
		}

		float current_angle = 0;
		float separation = float(6.28319/number_of_lines);
		for(int i = 0; i < number_of_lines; i++){
			float xp = sin(separation*i)*r;
			float yp = cos(separation*i)*r;
			if(use_texture){
				glTexCoord2f(xp, yp);
			}
			
			glVertex2d(xp, yp);
		}
}

void drawCircle(float x, float y, float r){
	glEnable2D();
	glTranslate2f(camera_x,camera_y);
	glTranslate2f(x,y);
	if(use_fill){
		glBegin(GL_POLYGON);
		setColor(fill_color);
		circle_helper(r);
		glEnd();
	}

	if (use_stroke){
		glBegin(GL_LINE_LOOP);
		setColor(stroke_color);
		circle_helper(r);
		glEnd();
	}	
	glDisable2D();
}

void drawCircle(Coord pos, float r){
	drawCircle((float)pos.x,(float)pos.y,r);
}

void fill(){
	use_fill = true;
}

void fill(Color c){
	fill();
	fill_color = c;
}

void noFill(){
	use_fill = false;
}

void stroke(){
	use_stroke = true;
}

void stroke(Color c){
	stroke();
	stroke_color = c;
}

void noStroke(){
	use_stroke = false;
}

void useTexture(GLuint id){
	glBindTexture(GL_TEXTURE_2D, id); 
	//glBindTexture(GL_TEXTURE_2D, texture1); 
	glEnable( GL_TEXTURE_2D );
	use_texture = true;
}

void noTexture(){
	use_texture = false;
	glDisable( GL_TEXTURE_2D );
}

void drawRect(Coord topleft, Coord bottomright){
	drawRect((float)topleft.x,(float)topleft.y,(float)bottomright.x,(float)bottomright.y);
}

void drawRect(float x1, float y1, float x2, float y2){
	glEnable2D();
	glTranslate2f(camera_x,camera_y);	
		if(use_texture){
			glEnable( GL_TEXTURE_2D );
			if(!use_fill){
				fill(Color(255,255,255,255));
			}		
		}
		if(use_fill){
			glBegin(GL_POLYGON);
			setColor(fill_color);
			rectHelper(x1,y1,x2,y2);
		}
		if(use_stroke){
			glBegin(GL_LINE_LOOP);
			setColor(stroke_color);
			rectHelper(x1,y1,x2,y2);
		}
	glDisable2D();
}
void rectHelper(float x1, float y1, float x2, float y2){	
		if(use_texture){
			glTexCoord2f(0.0f, 0.0f);glVertex2d( x1, y1);
			glTexCoord2f(1.0f, 0.0f);glVertex2d( x2, y1);
			glTexCoord2f(1.0f, 1.0f);glVertex2d( x2, y2); 
			glTexCoord2f(0.0f, 1.0f);glVertex2d( x1, y2);			
		}
		else{
			glVertex2d( x1, y1);
			glVertex2d( x2, y1);
			glVertex2d( x2, y2); 
			glVertex2d( x1, y2);	
		}
	
		glEnd();
}
//void drawTexRect(float x1, float y1, float x2, float y2){
//  glEnable2D();
//  glEnable( GL_TEXTURE_2D );
//  glBindTexture( GL_TEXTURE_2D, texture1 );
//	glBegin(GL_QUADS);
//	setColor(fill_color);	
//	setColor(Color(1.0f,1.0f,1.0f));	
//	glTexCoord2f(0.0f, 0.0f);glVertex2d( x1, y1);
//		glTexCoord2f(1.0f, 0.0f);glVertex2d( x2, y1);
//		glTexCoord2f(1.0f, 1.0f);glVertex2d( x2, y2); 
//		glTexCoord2f(0.0f, 1.0f);glVertex2d( x1, y2);		
//		//glTexCoord2d(0.0,0.0); glVertex2d(0.0,0.0);
//		//glTexCoord2d(1.0,0.0); glVertex2d(370,0.0);
//		//glTexCoord2d(1.0,1.0); glVertex2d(370,391);
//		//glTexCoord2d(0.0,1.0); glVertex2d(0.0,391);
//	glEnd();
//  glDisable2D();
//  glDisable( GL_TEXTURE_2D );
//}

void drawLine(float x1, float y1, float x2, float y2, Color c){
	drawLine(x2,y1,x2,y2,c,1);
}

void drawLine(float x1, float y1, float x2, float y2, Color c, int width){
  glEnable2D();
	glTranslate2f(camera_x,camera_y);
	  setColor(c);
		glLineWidth((float)width);
		glBegin(GL_LINES);
		glVertex2d( x1, y1);
		glVertex2d( x2, y2); 
	glEnd();
  glDisable2D();
}

void renderBitmapString( Coord pos, string *str, Color c) {
	char * chr = (char*)str->c_str();
 glEnable2D();
	  setColor(c);
	  glRasterPos2i(pos.x, pos.y);
	  for (chr; *chr != '\0'; chr++) {
		glutBitmapCharacter(GLUT_BITMAP_HELVETICA_12, *chr);
	  }
 glDisable2D();
}
void renderBitmapString( Coord pos, string *str) {
	renderBitmapString(pos, str, stroke_color);
}

GLuint findTexture(string s){
	string s1 = "Graphics\\";
	s = s1.append(s);
	for(unsigned int i = 0; i < textures.size(); i++){
		string s2 = textures[i]->getName();
		if (s.compare(s2)==0){
			GLuint id = textures[i]->getID();
			return textures[i]->getID();
		}
	}
	printf("texture %s not found\n",s.c_str());
	return 0;
}

void zoomIn(){
	camera_scale += camera_zoom_speed;
	if (camera_maxScale < camera_scale) camera_scale = camera_maxScale;
}
void zoomOut(){
	camera_scale -= camera_zoom_speed;
	if (camera_minScale > camera_scale) camera_scale = camera_minScale;
}
void moveCamera(float x, float y){
	camera_x += x;
	camera_y += y;
}
void setCamera(float x, float y){
	camera_x = x;
	camera_y = y;
}

float get_camera_x(){
	return camera_x;
}

float get_camera_y(){
	return camera_y;
}

Coord mouse_get_position(){
	return mouse_pos;
}
Coord mouse_get_world_position(){
	return mouse_worldPos;
}

void mouse_set_position(int xIn, int yIn){
	mouse_pos.x = xIn;
	mouse_pos.y = yIn;
	mouse_worldPos.x = xIn - (int)camera_x;
	mouse_worldPos.y = yIn - (int)camera_y;
}
bool mouse_left(){
	return mouse_lmb;
}
bool mouse_right(){
	return mouse_rmb;
}
bool mouse_middle(){
	return mouse_mmb;
}
void mouse_left_pressed(){
	mouse_lmb = true;
}
void mouse_right_pressed(){
	mouse_rmb = true;
}
void mouse_middle_pressed(){
	mouse_mmb = true;
}
void mouse_right_released(){
	mouse_rmb = false;
}
void mouse_left_released(){
	mouse_lmb = false;
}
void mouse_middle_released(){
	mouse_mmb = false;
}
int get_window_width(){
	return window_width;
}
int get_window_height(){
	return window_height;
}